<?php

/**
 * Description of ExportGeneratorRIFCS
 *
 * @author jay
 */
class ExportGeneratorRIFCS extends ExportGenerator {

    private $registryObjectGroup;
    private $defaultOriginatingSource;
    private $keyPrefix;
    private $propertyToken = '/';
    private $defaultLocationType = 'iso19139dcmiBox';
    private $rifcsTypeMappingList;
    private $urlLocationPattern;

    public function getRegistryObjectGroup() {
        return $this->registryObjectGroup;
    }

    public function setRegistryObjectGroup($registryObjectGroup) {
        $this->registryObjectGroup = $this->encodeSpecialCharacters($registryObjectGroup);
    }

    public function getKeyPrefix() {
        return $this->keyPrefix;
    }

    public function setKeyPrefix($keyPrefix) {
        $this->keyPrefix = $keyPrefix;
    }

    public function getUrlLocationPattern() {
        return $this->urlLocationPattern;
    }

    public function setUrlLocationPattern($urlLocationPattern) {
        $this->urlLocationPattern = $urlLocationPattern;
    }

    public function getDefaultOriginatingSource() {
        return $this->defaultOriginatingSource;
    }

    public function setDefaultOriginatingSource($defaultOriginatingSource) {
        $this->defaultOriginatingSource = $this->encodeSpecialCharacters($defaultOriginatingSource);
    }

    public function setRifcsTypeMappingListFromDoctrine($typeMappingList) {
        $this->rifcsTypeMappingList = array();
        foreach ($typeMappingList as $typeMapping) {
            $this->rifcsTypeMappingList[$typeMapping->getCollectionType()->getTypeValue()] =
                    array('objectClass' => $typeMapping->getRifcsObjectType()->getTypeValue(),
                        'objectType' => $typeMapping->getObjectTypeDescriptor());
        }
    }

    public function getRifcsTypeMappingList() {
        return $this->rifcsTypeMappingList;
    }

    private function generateRIFCSRelatedInfo(DOMNode $parent, CollectionItem $collectionItem) {

        foreach ($collectionItem->getPropertiesByIdentifier('related-info') as $collectionProperty) {
            $domElement = $parent->appendChild(new DOMElement('relatedInfo'));
            $domElement = $domElement->appendChild(new DOMElement('identifier', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue())));
            $domElement->setAttribute('type', 'uri');
        }
    }

    private function generateRIFCSRelatedObjects(DOMNode $parent, CollectionItem $collectionItem) {

        foreach ($collectionItem->getCollectionRelations() as $collectionRelation) {
            /**
             * Check that the related item is actually in the list of publishable
             * UIN's otherwise do not include it in the export
             */
            if (in_array($collectionRelation->getRelatedItemUin(), $this->publishableUinList)) {
                $domElement = $parent->appendChild(new DOMElement('relatedObject'));
                $domElement->appendChild(new DOMElement('key', $this->encodeSpecialCharacters($this->keyPrefix . $collectionRelation->getRelatedItemUin())));
                $domElement = $domElement->appendChild(new DOMElement('relation'));
                $domElement->setAttribute('type', $this->encodeSpecialCharacters($collectionRelation->getRelationType()->getTypeValue()));
            }
        }

        /**
         * Also provide relating collections
         */
        foreach ($collectionItem->getRelatingCollections() as $collectionRelation) {
            /**
             * Check that the related item is actually in the list of publishable
             * UIN's otherwise do not include it in the export
             */
            if (in_array($collectionRelation->getThisCollectionUin(), $this->publishableUinList)) {

                $domElement = $parent->appendChild(new DOMElement('relatedObject'));
                $domElement->appendChild(new DOMElement('key', $this->encodeSpecialCharacters($this->keyPrefix . $collectionRelation->getThisCollectionUin())));
                $domElement = $domElement->appendChild(new DOMElement('relation'));
                $domElement->setAttribute('type', $this->encodeSpecialCharacters($collectionRelation->getRelationType()->getValueInverse()));
            }
        }
    }

    private function generateRIFCSSubjects(DOMNode $parent, CollectionItem $collectionItem) {
        $arcSubjects = array();
        $localSubjects = array();
        foreach ($collectionItem->getPropertiesByIdentifier('subject') as $collectionProperty) {
            /**
             * ARC Code must be at the start of the subject value
             */
            if (strpos($collectionProperty->getPropertyValue(), 'arc-code' . $this->propertyToken) === 0) {
                /**
                 * This subject is an ARC code
                 */
                $arcSubjects[] = $this->encodeSpecialCharacters(substr($collectionProperty->getPropertyValue(), 9));
               
            } else {
                /**
                 * use the local subject identifier
                 */
                $localSubjects[] = $this->encodeSpecialCharacters($collectionProperty->getPropertyValue());
            }
        }

        foreach ($collectionItem->getCollectionTags() as $collectionTag) {
            $localSubjects[] = $collectionTag->getSubjectTag()->getTypeName();
        }

        /**
         * Specify ordering of subject to appease ANDS
         */
        foreach ($arcSubjects as $subject) {
            $domElement = $parent->appendChild(new DOMElement('subject',$subject));
                $domElement->setAttribute('type', 'anzsrc-for');
        }
        foreach ($localSubjects as $subject) {
            $domElement = $parent->appendChild(new DOMElement('subject',$subject));
                $domElement->setAttribute('type', 'local');
        }

    }

    private function generateRIFCSTimeSeriesLocations(DOMNode $parent, CollectionItem $collectionItem) {
        if (($collectionItem->getApplicableStart() != null) || ($collectionItem->getApplicableEnd() != null)) {
            $domElement = $parent->appendChild(new DOMElement('temporal'));
            if ($collectionItem->getApplicableStart() != null) {
                $dateElement = $domElement->appendChild(new DOMElement('date', date('c', strtotime($collectionItem->getApplicableStart()))));
                $dateElement->setAttribute('type', 'dateFrom');
                $dateElement->setAttribute('dateFormat', 'UTC');
            }
            if ($collectionItem->getApplicableEnd() != null) {
                $dateElement = $domElement->appendChild(new DOMElement('date', date('c', strtotime($collectionItem->getApplicableEnd()))));
                $dateElement->setAttribute('type', 'dateTo');
                $dateElement->setAttribute('dateFormat', 'UTC');
            }
        }
    }

    private function generateRIFCSSpatialLocations(DOMNode $parent, CollectionItem $collectionItem) {
        $domElement = $parent->appendChild(new DOMElement('coverage'));
        foreach ($collectionItem->getPropertiesByIdentifier('geo-location') as $collectionProperty) {
            $geoLocParts = explode($this->propertyToken, $collectionProperty->getPropertyValue(), 2);
            $locationForm = $this->defaultLocationType;
            $location = '';
            //IF the geolocation specifies a format then override the default dcmibox
            if (count($geoLocParts) > 1) {
                $locationForm = $geoLocParts[0];
                $location = $geoLocParts[1];
            } else {
                $location = $geoLocParts[0];
            }



            $spatialElement = $domElement->appendChild(new DOMElement('spatial', $this->encodeSpecialCharacters($location)));
            $spatialElement->setAttribute('type', $this->encodeSpecialCharacters($locationForm));
        }

        $this->generateRIFCSTimeSeriesLocations($domElement, $collectionItem);
    }

    private function generateRIFCSPhysicalLocations(DOMNode $parent, CollectionItem $collectionItem) {

        //$this->generateRIFCSSpatialLocations($parent, $collectionItem);
        /**
         * TODO: Implement the rest of me
         */
        /**
         * add any physical addresses
         */
        foreach ($collectionItem->getPropertiesByIdentifier('street-address') as $collectionProperty) {
            $domElement = $parent->appendChild(new DOMElement('location'));
            $domElement = $domElement->appendChild(new DOMElement('address'));
            $domElement = $domElement->appendChild(new DOMElement('physical'));
            $domElement->setAttribute('type', 'streetAddress');
            $domElement = $domElement->appendChild(new DOMElement('addressPart', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue())));
            $domElement->setAttribute('type', 'text');
        }

        /**
         * add any postal addresses
         */
        foreach ($collectionItem->getPropertiesByIdentifier('postal-address') as $collectionProperty) {
            $domElement = $parent->appendChild(new DOMElement('location'));
            $domElement = $domElement->appendChild(new DOMElement('address'));
            $domElement = $domElement->appendChild(new DOMElement('physical'));
            $domElement->setAttribute('type', 'postalAddress');
            $domElement = $domElement->appendChild(new DOMElement('addressPart', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue())));
            $domElement->setAttribute('type', 'text');
        }
    }

    private function generateRIFCSElectronicLocations(DOMNode $parent, CollectionItem $collectionItem) {
        /**
         * usethe supplied pattern to generate the URL for this instances
         * view of the collection
         */
        $calculatedUrl = str_replace('{uin}', $collectionItem->getUin(), $this->urlLocationPattern);

        $domElement = $parent->appendChild(new DOMElement('location'));
        $domElement = $domElement->appendChild(new DOMElement('address'));
        $domElement = $domElement->appendChild(new DOMElement('electronic'));
        $domElement->setAttribute('type', 'url');
        $domElement = $domElement->appendChild(new DOMElement('value', $this->encodeSpecialCharacters($calculatedUrl)));

        /**
         * add any additional URl locators from the properties
         */
        foreach ($collectionItem->getPropertiesByIdentifier('locator') as $collectionProperty) {
            $domElement = $parent->appendChild(new DOMElement('location'));
            $domElement = $domElement->appendChild(new DOMElement('address'));
            $domElement = $domElement->appendChild(new DOMElement('electronic'));
            $domElement->setAttribute('type', 'url');
            $domElement = $domElement->appendChild(new DOMElement('value', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue())));
        }


        /**
         * add any phone addresses
         */
        foreach ($collectionItem->getPropertiesByIdentifier('phone') as $collectionProperty) {
            $domElement = $parent->appendChild(new DOMElement('location'));
            $domElement = $domElement->appendChild(new DOMElement('address'));
            $domElement = $domElement->appendChild(new DOMElement('electronic'));
            $domElement->setAttribute('type', 'voice');
            $domElement = $domElement->appendChild(new DOMElement('value', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue())));
        }

        /**
         * add any email addresses
         */
        foreach ($collectionItem->getPropertiesByIdentifier('email') as $collectionProperty) {
            $domElement = $parent->appendChild(new DOMElement('location'));
            $domElement = $domElement->appendChild(new DOMElement('address'));
            $domElement = $domElement->appendChild(new DOMElement('electronic'));
            $domElement->setAttribute('type', 'email');
            $domElement = $domElement->appendChild(new DOMElement('value', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue())));
        }
    }

    private function generateRIFCSLocations(DOMNode $parent, CollectionItem $collectionItem) {
        $this->generateRIFCSSpatialLocations($parent, $collectionItem);
        $this->generateRIFCSPhysicalLocations($parent, $collectionItem);
        $this->generateRIFCSElectronicLocations($parent, $collectionItem);
    }

    private function generateRIFCSDescriptions(DOMNode $parent, CollectionItem $collectionItem) {
        //Brief Description
        $descriptionText = '';
        foreach ($collectionItem->getPropertiesByIdentifier('description-brief') as $collectionProperty) {
            if (strlen($descriptionText) > 0) {
                $descriptionText .= ' ';
            }
            $descriptionText .= $collectionProperty->getPropertyValue();
        }

        if ($descriptionText != '') {
            $domElement = $parent->appendChild(new DOMElement('description', $this->encodeSpecialCharacters($descriptionText)));
            $domElement->setAttribute('type', 'brief');
        }

        //Full Description
        $descriptionText = '';
        foreach ($collectionItem->getPropertiesByIdentifier('description-full') as $collectionProperty) {
            if (strlen($descriptionText) > 0) {
                $descriptionText .= ' ';
            }
            $descriptionText .= $collectionProperty->getPropertyValue();
        }

        if ($descriptionText != '') {
            $domElement = $parent->appendChild(new DOMElement('description', $this->encodeSpecialCharacters($descriptionText)));
            $domElement->setAttribute('type', 'full');
        }

        //collection Rights Description
        $descriptionText = '';
        foreach ($collectionItem->getPropertiesByIdentifier('description-rights') as $collectionProperty) {
            if (strlen($descriptionText) > 0) {
                $descriptionText .= ' ';
            }
            $descriptionText .= $collectionProperty->getPropertyValue();
        }

        if ($descriptionText != '') {
            $domElement = $parent->appendChild(new DOMElement('description', $this->encodeSpecialCharacters($descriptionText)));
            $domElement->setAttribute('type', 'rights');
        }

        //access rights Description
        $descriptionText = '';
        foreach ($collectionItem->getPropertiesByIdentifier('description-access-rights') as $collectionProperty) {
            if (strlen($descriptionText) > 0) {
                $descriptionText .= ' ';
            }
            $descriptionText .= $collectionProperty->getPropertyValue();
        }

        if ($descriptionText != '') {
            $domElement = $parent->appendChild(new DOMElement('description', $this->encodeSpecialCharacters($descriptionText)));
            $domElement->setAttribute('type', 'access rights');
        }
    }

    private function generateRIFCSNameParts(DOMNode $parent, CollectionItem $collectionItem) {
        $primarySet = false;
        /**
         * Alternative Names
         */
        foreach ($collectionItem->getPropertiesByIdentifier('alt-name') as $collectionProperty) {
            $domElement = $parent->appendChild(new DOMElement('name'));
            $domElement->setAttribute('type', 'alternative');
            $domElement->appendChild(new DOMElement('namePart', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue())));
        }

        /**
         * Insert the Party names if they exist
         */
        $nameParts = $collectionItem->getCompressedPropertyValueArrayForIdentifiers(array('name-family', 'name-given', 'name-salutation'), false, true);
        if (count($nameParts) > 0) {
            $domElement = $parent->appendChild(new DOMElement('name'));
            $domElement->setAttribute('type', 'primary');

            if (key_exists('name-family', $nameParts)) {
                $nameElement = $domElement->appendChild(new DOMElement('namePart', $this->encodeSpecialCharacters($nameParts['name-family'])));
                $nameElement->setAttribute('type', 'family');
            }

            if (key_exists('name-given', $nameParts)) {
                $nameElement = $domElement->appendChild(new DOMElement('namePart', $this->encodeSpecialCharacters($nameParts['name-given'])));
                $nameElement->setAttribute('type', 'given');
            }

            if (key_exists('name-salutation', $nameParts)) {
                $nameElement = $domElement->appendChild(new DOMElement('namePart', $this->encodeSpecialCharacters($nameParts['name-salutation'])));
                $nameElement->setAttribute('type', 'title');
            }


            $primarySet = true;
        }

        /**
         * Insert the primary name (this becomes an alternative name if atleast
         * one Party name is set)
         */
        
        /**
         * ANDS does not want the collection name for person records
         * easy way to tell is if the primary has already been set, (i.e. firstname/lastname etc)
         * then don't output the collection name         *
         */
        if (! $primarySet) {
            $domElement = $parent->appendChild(new DOMElement('name'));
            $domElement->setAttribute('type', 'primary');
            $domElement->appendChild(new DOMElement('namePart', $this->encodeSpecialCharacters($collectionItem->getCollectionName())));
        }
        
    }

    private function generateRIFCSCollectionDetails(DOMNode $parent, CollectionItem $collectionItem) {
        //$objectClassType =
        $objectClass = '';
        $objectType = '';
        if (key_exists($collectionItem->getCollectionType()->getTypeValue(), $this->rifcsTypeMappingList)) {
            $typeMapping = $this->rifcsTypeMappingList[$collectionItem->getCollectionType()->getTypeValue()];
            if ($typeMapping != null) {
                $objectClass = $typeMapping['objectClass'];
                $objectType = $typeMapping['objectType'];
            }
        }

        if ($objectClass != '') {

            $domElement = $parent->appendChild(new DOMElement($objectClass));
            if ($objectType != '') {
                $domElement->setAttribute('type', $objectType);
            }
            /**
             * Issue due to RIF-CS format where only a 'Collection' can have
             * a date accessioned - this hardcoded hack must be put in place
             *
             * and that an activity does not have a dateModified
             */
            if ((strtoupper($objectClass) == 'COLLECTION') || (strtoupper($objectClass) == 'PARTY')) {
                if (strtoupper($objectClass) == 'COLLECTION') {
                    $domElement->setAttribute('dateAccessioned', date('c', strtotime($collectionItem->getCreatedAt())));
                }
                $domElement->setAttribute('dateModified', date('c', strtotime($collectionItem->getUpdatedAt())));
            }

            $identifierElement = $domElement->appendChild(new DOMElement('identifier', $this->encodeSpecialCharacters($this->keyPrefix . $collectionItem->getUin())));
            $identifierElement->setAttribute('type', 'local');

            $this->generateRIFCSNameParts($domElement, $collectionItem);
            $this->generateRIFCSRelatedObjects($domElement, $collectionItem);
            $this->generateRIFCSRelatedInfo($domElement, $collectionItem);
            $this->generateRIFCSSubjects($domElement, $collectionItem);
            $this->generateRIFCSLocations($domElement, $collectionItem);
            $this->generateRIFCSDescriptions($domElement, $collectionItem);
        }
    }

    public function generateRIFCSRegistryObject(DOMNode $parent, CollectionItem $collectionItem) {
        /**
         * Deleted Objects are not exported
         */
        if (($collectionItem->getDeletedAt() == null) || ($collectionItem->getDeletedAt() == '')) {
            $domElement = $parent->appendChild(new DOMElement('registryObject'));





            $domElement->setAttribute('group', $this->registryObjectGroup);
            $domElement->appendChild(new DOMElement('key', $this->encodeSpecialCharacters($this->keyPrefix . $collectionItem->getUin())));

            $useDefaultOrigin = true;
            foreach ($collectionItem->getPropertiesByIdentifier('rifcs-originating-source') as $collectionProperty) {
                $domElement->setAttribute('group', $this->encodeSpecialCharacters($collectionProperty->getPropertyValue()));
                $useDefaultOrigin = false;
            }
            if ($useDefaultOrigin) {
                $domElement->appendChild(new DOMElement('originatingSource', $this->encodeSpecialCharacters($this->defaultOriginatingSource)));
            }

            $this->generateRIFCSCollectionDetails($domElement, $collectionItem);
        }

        $this->resetDoctrineConnection();
    }

    public function generateExportFromCollections($collectionList) {
        $this->setPublishableUinList($collectionList);
        $exportDoc = new DOMDocument('1.0', 'utf-8');
        //Leave this hear to make debugging easier
        $exportDoc->formatOutput = true;
        $domElement = $exportDoc->createElementNS('http://ands.org.au/standards/rif-cs/registryObjects', 'registryObjects');
        $domElement = $exportDoc->appendChild($domElement);
        $domElement->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', 'http://ands.org.au/standards/rif-cs/registryObject http://services.ands.org.au/home/orca/schemata.registryObjects.xsd');

        foreach ($collectionList as $collectionItem) {
            $this->generateRIFCSRegistryObject($domElement, $collectionItem);
        }
        return $exportDoc;
    }

}

?>
